package org.xtlgen;

import java.awt.geom.GeneralPath;

import org.w3c.dom.Node;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Element;

/**
 * Represents a Point in the XtlGen system.
 * <p>
 * A Point must be specified like this:
 * </p>
 * <pre>
 * &lt;Point x="[x_position]" y="[y_position]"&gt;
 * &lt;/Point&gt;
 * </pre>
 * or this:
 * <pre>
 * &lt;Point x="[x_position]" y="[y_position]"/&gt;
 * </pre>
 * in the configuration file.
 */
public class Point extends Shape {
  /**
   * Construct a Point.
   *
   * @param parent  the parent Shape, null allowed
   * @param params  parameters for this Shape as read from the config file
   */
  public Point(Shape parent, Element params) {
    super(parent, params);
  }

  /**
   * Access the X coordinate.
   * @return the X coordinate.
   */
  public double getX() {
    return x;
  }
  
  /**
   * Access the Y coordinate.
   * @return the Y coordinate.
   */
  public double getY() {
    return y;
  }
  
  /**
   * HashCode.
   * @return the hashCode for this Point
   */
  public int hashCode () {
    int hash = 0;
    long bits = Double.doubleToLongBits(x);
    
    hash = (31*hash) ^ (int)(bits ^ (bits >> 32));
    
    bits = Double.doubleToLongBits(y);
    hash = (31*hash) ^ (int)(bits ^ (bits >> 32));
    
    return hash;
  }
    
  /**
   * Create the encapsulated AWT Shape (a GeneralPath).
   *
   * @param params  parameters for this Shape as read from the config file
   *
   * @return A GeneralPath.
   *
   * @throws IllegalArgumentException if one of the required parameters cannot
   *         be found on the given params object.
   */
  protected java.awt.Shape createAWTShape(Element params) {
    GeneralPath result = null;
    NamedNodeMap attributes = params.getAttributes();
    
    if (attributes == null) {
      throw new IllegalArgumentException("Point requires the x and y attributes");
    }
    else {
      try {
        ShapeAttributes shapeAttributes = new ShapeAttributes(attributes);
        x = shapeAttributes.getDouble("x");
        y = shapeAttributes.getDouble("y");
        
        // To display a point with an AWT Shape we create a line with
        // both ends in the same place.
        result = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 2);
        result.moveTo((float)x, (float)y);
        result.lineTo((float)x, (float)y);
      }
      catch(IllegalArgumentException e) {
        throw new IllegalArgumentException("Point: " + e.getMessage());
      }
    }

    return result;
  }

  /**
   * Clip the AWT shape to the given parent bounds.
   *
   * @param parent parent Shape
   * @param shape AWT shape to clip
   *
   * @return The resulting clipped AWT shape or null if completely clipped.
   */
  protected java.awt.Shape clipAWTShape(Shape parent, java.awt.Shape shape) {
    if (parent.getAWTShape() != null) {
      if (parent.getAWTShape().contains(x, y)) {
        return shape;
      }
      return null;
    }
    return shape;
  }

  /**
   * Create a string representation of this Point.
   */
  public String toString() {
    return "org.xtlgen.Point[" + x + "," + y + "]";
  }
  
  /*
   * Static block of code used to register a ShapeFactory for Points.
   */
  static {
    Shape.registerShapeFactory(
      "Point",
      new ShapeFactory() {
        public Shape makeShape(Shape parent, Element node) {
          return new Point(parent, node);
        }
      });
  }

  /*
   * Fields
   */
  private double x;
  private double y;
}